package com.artisan.requestbodycache.wrapper;

import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * 可重复读取的 HttpServletRequest 包装类
 * 核心思路：将请求体缓存到内存，支持多次读取
 */
public class CachedHttpServletRequest extends HttpServletRequestWrapper {
    /** 缓存字节数组，包级可见便于测试 */
    private byte[] bodyCache;

    public CachedHttpServletRequest(HttpServletRequest request) throws IOException {
        super(request);
        // 仅缓存一次，后续任意次读取
        try (InputStream is = request.getInputStream()) {
            // 安全提示：可自行限制最大长度，防止大报文 OOM
            bodyCache = is.readAllBytes(); // JDK9+
        }
    }

    @Override
    public ServletInputStream getInputStream() {
        return new CachedServletInputStream(bodyCache);
    }

    @Override
    public BufferedReader getReader() {
        String encoding = getCharacterEncoding();
        if (encoding == null) {
            encoding = StandardCharsets.UTF_8.name();
        }
        return new BufferedReader(new InputStreamReader(getInputStream(), 
            java.nio.charset.Charset.forName(encoding)));
    }

    /**
     * 获取缓存的请求体字节数组（方便其他组件使用）
     */
    public byte[] getBodyCache() {
        return bodyCache;
    }

    /* ================= 自定义输入流 ================= */
    private static class CachedServletInputStream extends ServletInputStream {
        private final ByteArrayInputStream buffer;

        public CachedServletInputStream(byte[] data) {
            this.buffer = new ByteArrayInputStream(data);
        }

        @Override
        public boolean isFinished() {
            return buffer.available() == 0;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) {
            throw new UnsupportedOperationException("异步 IO 未实现");
        }

        @Override
        public int read() {
            return buffer.read();
        }
    }
}

